🎖️GitЯра🎖️
src/helpers/NRF52Board.cpp 890a2e2cffa98dea3ca88db3c3aba72ef23ff3f7 (890a2e2c) Text, 14.35 KB
Tff7b72#Tff7b72if defined(NRF52_PLATFORM)
Tff7b72#Tff7b72include T8b949e"NRF52Board.h"
Tff7b72#Tff7b72include T8b949e<target.h>
Tff7b72#Tff7b72include T8b949e<bluefruit.h>
Tff7b72#Tff7b72include T8b949e<nrf_soc.h>
Tff7b72#Tff7b72ifdef USE_CC310_HW_CRYPTO
Tff7b72#Tff7b72include T8b949e<Adafruit_nRFCrypto.h>
Tff7b72#Tff7b72endif
Tff7b72static Te6edf3BLEDfu Te6edf3bledfuTb4b4b4;
Tff7b72static Tffa657void Td2a8ffconnect_callbackTb4b4b4(Tffa657uint16_t Te6edf3conn_handleTb4b4b4) Tb4b4b4{
Tb4b4b4(Tffa657voidTb4b4b4)Te6edf3conn_handleTb4b4b4;
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffBLE client connectedTa5d6ff"Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72static Tffa657void Td2a8ffdisconnect_callbackTb4b4b4(Tffa657uint16_t Te6edf3conn_handleTb4b4b4, Tffa657uint8_t Te6edf3reasonTb4b4b4) Tb4b4b4{
Tb4b4b4(Tffa657voidTb4b4b4)Te6edf3conn_handleTb4b4b4;
Tb4b4b4(Tffa657voidTb4b4b4)Te6edf3reasonTb4b4b4;
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffBLE client disconnectedTa5d6ff"Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::beginTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3startup_reason Tff7b72= Te6edf3BD_STARTUP_NORMALTb4b4b4;
Tff7b72#Tff7b72ifdef USE_CC310_HW_CRYPTO
T8b949e// CC310 TRNG is higher quality and environment-independent vs radio RSSI noise.
Te6edf3nRFCryptoTb4b4b4.Te6edf3beginTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
Tb4b4b4}
Tff7b72#Tff7b72ifdef NRF52_POWER_MANAGEMENT
Tff7b72#Tff7b72include T8b949e"nrf.h"
T8b949e// Power Management global variables
Tffa657uint32_t Te6edf3g_nrf52_reset_reason Tff7b72= T79c0ff0Tb4b4b4; T8b949e// Reset/Startup reason
Tffa657uint8_t Te6edf3g_nrf52_shutdown_reason Tff7b72= T79c0ff0Tb4b4b4; T8b949e// Shutdown reason
T8b949e// Early constructor - runs before SystemInit() clears the registers
T8b949e// Priority 101 ensures this runs before SystemInit (102) and before
T8b949e// any C++ static constructors (default 65535)
Tff7b72static Tffa657void Td2a8ff__attribute__Tb4b4b4(Tb4b4b4(Te6edf3constructorTb4b4b4(T79c0ff101Tb4b4b4)Tb4b4b4)Tb4b4b4) Te6edf3nrf52_early_reset_captureTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3g_nrf52_reset_reason Tff7b72= Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3RESETREASTb4b4b4;
Te6edf3g_nrf52_shutdown_reason Tff7b72= Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3GPREGRET2Tb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::initPowerMgrTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Copy early-captured register values
Te6edf3reset_reason Tff7b72= Te6edf3g_nrf52_reset_reasonTb4b4b4;
Te6edf3shutdown_reason Tff7b72= Te6edf3g_nrf52_shutdown_reasonTb4b4b4;
Te6edf3boot_voltage_mv Tff7b72= T79c0ff0Tb4b4b4; T8b949e// Will be set by checkBootVoltage()
T8b949e// Clear registers for next boot
T8b949e// Note: At this point SoftDevice may or may not be enabled
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Te6edf3sd_power_reset_reason_clrTb4b4b4(T79c0ff0xFFFFFFFFTb4b4b4)Tb4b4b4;
Te6edf3sd_power_gpregret_clrTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff0xFFTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3RESETREAS Tff7b72= T79c0ff0xFFFFFFFFTb4b4b4; T8b949e// Write 1s to clear
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3GPREGRET2 Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
T8b949e// Log reset/shutdown info
Tff7b72if Tb4b4b4(Te6edf3shutdown_reason Tff7b72!Tff7b72= Te6edf3SHUTDOWN_REASON_NONETb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Reset = %s (0x%lX); Shutdown = %s (0x%02X)Ta5d6ff"Tb4b4b4,
Te6edf3getResetReasonStringTb4b4b4(Te6edf3reset_reasonTb4b4b4)Tb4b4b4, Tb4b4b4(Tffa657unsigned Tffa657longTb4b4b4)Te6edf3reset_reasonTb4b4b4,
Te6edf3getShutdownReasonStringTb4b4b4(Te6edf3shutdown_reasonTb4b4b4)Tb4b4b4, Te6edf3shutdown_reasonTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Reset = %s (0x%lX)Ta5d6ff"Tb4b4b4,
Te6edf3getResetReasonStringTb4b4b4(Te6edf3reset_reasonTb4b4b4)Tb4b4b4, Tb4b4b4(Tffa657unsigned Tffa657longTb4b4b4)Te6edf3reset_reasonTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72const Tffa657charTff7b72* Td2a8ffNRF52Board::getResetReasonStringTb4b4b4(Tffa657uint32_t Te6edf3reasonTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_RESETPIN_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffReset PinTa5d6ff"Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_DOG_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffWatchdogTa5d6ff"Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_SREQ_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffSoft ResetTa5d6ff"Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_LOCKUP_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffCPU LockupTa5d6ff"Tb4b4b4;
Tff7b72#Tff7b72ifdef POWER_RESETREAS_LPCOMP_Msk
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_LPCOMP_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffWake from LPCOMPTa5d6ff"Tb4b4b4;
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72ifdef POWER_RESETREAS_VBUS_Msk
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_VBUS_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffWake from VBUSTa5d6ff"Tb4b4b4;
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72ifdef POWER_RESETREAS_OFF_Msk
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_OFF_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffWake from GPIOTa5d6ff"Tb4b4b4;
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72ifdef POWER_RESETREAS_DIF_Msk
Tff7b72if Tb4b4b4(Te6edf3reason Tff7b72& Te6edf3POWER_RESETREAS_DIF_MskTb4b4b4) Tff7b72return Ta5d6ff"Ta5d6ffDebug InterfaceTa5d6ff"Tb4b4b4;
Tff7b72#Tff7b72endif
Tff7b72return Ta5d6ff"Ta5d6ffCold BootTa5d6ff"Tb4b4b4;
Tb4b4b4}
Tff7b72const Tffa657charTff7b72* Td2a8ffNRF52Board::getShutdownReasonStringTb4b4b4(Tffa657uint8_t Te6edf3reasonTb4b4b4) Tb4b4b4{
Tff7b72switch Tb4b4b4(Te6edf3reasonTb4b4b4) Tb4b4b4{
Tff7b72case Tff7b72SHUTDOWN_REASON_LOW_VOLTAGETb4b4b4: Tff7b72return Ta5d6ff"Ta5d6ffLow VoltageTa5d6ff"Tb4b4b4;
Tff7b72case Tff7b72SHUTDOWN_REASON_USERTb4b4b4: Tff7b72return Ta5d6ff"Ta5d6ffUser RequestTa5d6ff"Tb4b4b4;
Tff7b72case Tff7b72SHUTDOWN_REASON_BOOT_PROTECTTb4b4b4: Tff7b72return Ta5d6ff"Ta5d6ffBoot ProtectionTa5d6ff"Tb4b4b4;
Tb4b4b4}
Tff7b72return Ta5d6ff"Ta5d6ffUnknownTa5d6ff"Tb4b4b4;
Tb4b4b4}
Tffa657bool Td2a8ffNRF52Board::checkBootVoltageTb4b4b4(Tff7b72const Te6edf3PowerMgtConfigTff7b72* Te6edf3configTb4b4b4) Tb4b4b4{
Te6edf3initPowerMgrTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Read boot voltage
Te6edf3boot_voltage_mv Tff7b72= Te6edf3getBattMilliVoltsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3configTff7b72-Tff7b72>Te6edf3voltage_bootlock Tff7b72=Tff7b72= T79c0ff0Tb4b4b4) Tff7b72return Tffa657trueTb4b4b4; T8b949e// Protection disabled
T8b949e// Skip check if externally powered
Tff7b72if Tb4b4b4(Te6edf3isExternalPoweredTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Boot check skipped (external power)Ta5d6ff"Tb4b4b4)Tb4b4b4;
Te6edf3boot_voltage_mv Tff7b72= Te6edf3getBattMilliVoltsTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Tffa657trueTb4b4b4;
Tb4b4b4}
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Boot voltage = %u mV (threshold = %u mV)Ta5d6ff"Tb4b4b4,
Te6edf3boot_voltage_mvTb4b4b4, Te6edf3configTff7b72-Tff7b72>Te6edf3voltage_bootlockTb4b4b4)Tb4b4b4;
T8b949e// Only trigger shutdown if reading is valid (>1000mV) AND below threshold
T8b949e// This prevents spurious shutdowns on ADC glitches or uninitialized reads
Tff7b72if Tb4b4b4(Te6edf3boot_voltage_mv Tff7b72> T79c0ff1000 Tff7b72&Tff7b72& Te6edf3boot_voltage_mv Tff7b72< Te6edf3configTff7b72-Tff7b72>Te6edf3voltage_bootlockTb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Boot voltage too low - entering protective shutdownTa5d6ff"Tb4b4b4)Tb4b4b4;
Te6edf3initiateShutdownTb4b4b4(Te6edf3SHUTDOWN_REASON_BOOT_PROTECTTb4b4b4)Tb4b4b4;
Tff7b72return Tffa657falseTb4b4b4; T8b949e// Should never reach this
Tb4b4b4}
Tff7b72return Tffa657trueTb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::initiateShutdownTb4b4b4(Tffa657uint8_t Te6edf3reasonTb4b4b4) Tb4b4b4{
Te6edf3enterSystemOffTb4b4b4(Te6edf3reasonTb4b4b4)Tb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::enterSystemOffTb4b4b4(Tffa657uint8_t Te6edf3reasonTb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: Entering SYSTEMOFF (%s)Ta5d6ff"Tb4b4b4, Te6edf3getShutdownReasonStringTb4b4b4(Te6edf3reasonTb4b4b4)Tb4b4b4)Tb4b4b4;
T8b949e// Record shutdown reason in GPREGRET2
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Te6edf3sd_power_gpregret_clrTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff0xFFTb4b4b4)Tb4b4b4;
Te6edf3sd_power_gpregret_setTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3reasonTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3GPREGRET2 Tff7b72= Te6edf3reasonTb4b4b4;
Tb4b4b4}
T8b949e// Flush serial buffers
Te6edf3SerialTb4b4b4.Te6edf3flushTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3delayTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4;
T8b949e// Enter SYSTEMOFF
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Tffa657uint32_t Te6edf3err Tff7b72= Te6edf3sd_power_system_offTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3err Tff7b72=Tff7b72= Te6edf3NRF_ERROR_SOFTDEVICE_NOT_ENABLEDTb4b4b4) Tb4b4b4{ T8b949e//SoftDevice not enabled
Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
T8b949e// SoftDevice not available; write directly to POWER->SYSTEMOFF
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3SYSTEMOFF Tff7b72= Te6edf3POWER_SYSTEMOFF_SYSTEMOFF_EnterTb4b4b4;
Tb4b4b4}
T8b949e// If we get here, something went wrong. Reset to recover.
Te6edf3NVIC_SystemResetTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::configureVoltageWakeTb4b4b4(Tffa657uint8_t Te6edf3ain_channelTb4b4b4, Tffa657uint8_t Te6edf3refselTb4b4b4) Tb4b4b4{
T8b949e// LPCOMP is not managed by SoftDevice - direct register access required
T8b949e// Halt and disable before reconfiguration
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3TASKS_STOP Tff7b72= T79c0ff1Tb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3ENABLE Tff7b72= Te6edf3LPCOMP_ENABLE_ENABLE_DisabledTb4b4b4;
T8b949e// Select analog input (AIN0-7 maps to PSEL 0-7)
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3PSEL Tff7b72= Tb4b4b4(Tb4b4b4(Tffa657uint32_tTb4b4b4)Te6edf3ain_channel Tff7b72<Tff7b72< Te6edf3LPCOMP_PSEL_PSEL_PosTb4b4b4) Tff7b72& Te6edf3LPCOMP_PSEL_PSEL_MskTb4b4b4;
T8b949e// Reference: REFSEL (0-6=1/8..7/8, 7=ARef, 8-15=1/16..15/16)
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3REFSEL Tff7b72= Tb4b4b4(Tb4b4b4(Tffa657uint32_tTb4b4b4)Te6edf3refsel Tff7b72<Tff7b72< Te6edf3LPCOMP_REFSEL_REFSEL_PosTb4b4b4) Tff7b72& Te6edf3LPCOMP_REFSEL_REFSEL_MskTb4b4b4;
T8b949e// Detect UP events (voltage rises above threshold for battery recovery)
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3ANADETECT Tff7b72= Te6edf3LPCOMP_ANADETECT_ANADETECT_UpTb4b4b4;
T8b949e// Enable 50mV hysteresis for noise immunity
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3HYST Tff7b72= Te6edf3LPCOMP_HYST_HYST_Hyst50mVTb4b4b4;
T8b949e// Clear stale events/interrupts before enabling wake
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3EVENTS_READY Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3EVENTS_DOWN Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3EVENTS_UP Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3EVENTS_CROSS Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3INTENCLR Tff7b72= T79c0ff0xFFFFFFFFTb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3INTENSET Tff7b72= Te6edf3LPCOMP_INTENSET_UP_MskTb4b4b4;
T8b949e// Enable LPCOMP
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3ENABLE Tff7b72= Te6edf3LPCOMP_ENABLE_ENABLE_EnabledTb4b4b4;
Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3TASKS_START Tff7b72= T79c0ff1Tb4b4b4;
T8b949e// Wait for comparator to settle before entering SYSTEMOFF
Tff7b72for Tb4b4b4(Tffa657uint8_t Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff20 Tff7b72&Tff7b72& Tff7b72!Te6edf3NRF_LPCOMPTff7b72-Tff7b72>Te6edf3EVENTS_READYTb4b4b4; Te6edf3iTff7b72+Tff7b72+Tb4b4b4) Tb4b4b4{
Te6edf3delayMicrosecondsTb4b4b4(T79c0ff50Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3refsel Tff7b72=Tff7b72= T79c0ff7Tb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: LPCOMP wake configured (AIN%d, ref=ARef)Ta5d6ff"Tb4b4b4, Te6edf3ain_channelTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tff7b72if Tb4b4b4(Te6edf3refsel Tff7b72<Tff7b72= T79c0ff6Tb4b4b4) Tb4b4b4{
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: LPCOMP wake configured (AIN%d, ref=%d/8 VDD)Ta5d6ff"Tb4b4b4,
Te6edf3ain_channelTb4b4b4, Te6edf3refsel Tff7b72+ T79c0ff1Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tffa657uint8_t Te6edf3ref_num Tff7b72= Tb4b4b4(Tffa657uint8_tTb4b4b4)Tb4b4b4(Tb4b4b4(Te6edf3refsel Tff7b72- T79c0ff8Tb4b4b4) Tff7b72* T79c0ff2 Tff7b72+ T79c0ff1Tb4b4b4)Tb4b4b4;
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: LPCOMP wake configured (AIN%d, ref=%d/16 VDD)Ta5d6ff"Tb4b4b4,
Te6edf3ain_channelTb4b4b4, Te6edf3ref_numTb4b4b4)Tb4b4b4;
Tb4b4b4}
T8b949e// Configure VBUS (USB power) wake alongside LPCOMP
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Te6edf3sd_power_usbdetected_enableTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3EVENTS_USBDETECTED Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3INTENSET Tff7b72= Te6edf3POWER_INTENSET_USBDETECTED_MskTb4b4b4;
Tb4b4b4}
Te6edf3MESH_DEBUG_PRINTLNTb4b4b4(Ta5d6ff"Ta5d6ffPWRMGT: VBUS wake configuredTa5d6ff"Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72#Tff7b72endif
Tffa657void Td2a8ffNRF52BoardDCDC::beginTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3NRF52BoardTff7b72:Tff7b72:Te6edf3beginTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Enable DC/DC converter for improved power efficiency
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Te6edf3sd_power_dcdc_mode_setTb4b4b4(Te6edf3NRF_POWER_DCDC_ENABLETb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3DCDCEN Tff7b72= T79c0ff1Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tffa657bool Td2a8ffNRF52Board::isExternalPoweredTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Check if SoftDevice is enabled before using its API
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Tffa657uint32_t Te6edf3usb_statusTb4b4b4;
Te6edf3sd_power_usbregstatus_getTb4b4b4(Tff7b72&Te6edf3usb_statusTb4b4b4)Tb4b4b4;
Tff7b72return Tb4b4b4(Te6edf3usb_status Tff7b72& Te6edf3POWER_USBREGSTATUS_VBUSDETECT_MskTb4b4b4) Tff7b72!Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72return Tb4b4b4(Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3USBREGSTATUS Tff7b72& Te6edf3POWER_USBREGSTATUS_VBUSDETECT_MskTb4b4b4) Tff7b72!Tff7b72= T79c0ff0Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::sleepTb4b4b4(Tffa657uint32_t Te6edf3secsTb4b4b4) Tb4b4b4{
T8b949e// Clear FPU interrupt flags to avoid insomnia
T8b949e// see errata 87 for details https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_87.html
Tff7b72#Tff7b72if (__FPU_USED == 1)
Te6edf3__set_FPSCRTb4b4b4(Te6edf3__get_FPSCRTb4b4b4(Tb4b4b4) Tff7b72& Tff7b72~Tb4b4b4(T79c0ff0x0000009FTb4b4b4)Tb4b4b4)Tb4b4b4;
Tb4b4b4(Tffa657voidTb4b4b4) Te6edf3__get_FPSCRTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3NVIC_ClearPendingIRQTb4b4b4(Te6edf3FPU_IRQnTb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
T8b949e// On nRF52, we use event-driven sleep instead of timed sleep
T8b949e// The 'secs' parameter is ignored - we wake on any interrupt
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
T8b949e// first call processes pending softdevice events, second call sleeps.
Te6edf3sd_app_evt_waitTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3sd_app_evt_waitTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// softdevice is disabled, use raw WFE
Te6edf3__SEVTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3__WFETb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3__WFETb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
T8b949e// Temperature from NRF52 MCU
Tffa657float Td2a8ffNRF52Board::getMCUTemperatureTb4b4b4(Tb4b4b4) Tb4b4b4{
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{
Tffa657uint32_t Te6edf3err_codeTb4b4b4;
Tffa657int32_t Te6edf3tempTb4b4b4;
Te6edf3err_code Tff7b72= Te6edf3sd_temp_getTb4b4b4(Tff7b72&Te6edf3tempTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3err_code Tff7b72=Tff7b72= Te6edf3NRF_SUCCESSTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4(Tffa657floatTb4b4b4)Te6edf3temp Tff7b72* T79c0ff0.25fTb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72return Te6edf3NANTb4b4b4;
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3TASKS_START Tff7b72= T79c0ff1Tb4b4b4; T8b949e// Start temperature measurement
Tffa657long Te6edf3startTime Tff7b72= Te6edf3millisTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72while Tb4b4b4(Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3EVENTS_DATARDY Tff7b72=Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{ T8b949e// Wait for completion. Should complete in 50us
Tff7b72ifTb4b4b4(Te6edf3millisTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3startTime Tff7b72> T79c0ff5Tb4b4b4) Tb4b4b4{ T8b949e// To wait 5ms just in case
Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3TASKS_STOP Tff7b72= T79c0ff1Tb4b4b4;
Tff7b72return Te6edf3NANTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3EVENTS_DATARDY Tff7b72= T79c0ff0Tb4b4b4; T8b949e// Clear event flag
Tffa657int32_t Te6edf3temp Tff7b72= Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3TEMPTb4b4b4; T8b949e// In 0.25 *C units
Te6edf3NRF_TEMPTff7b72-Tff7b72>Te6edf3TASKS_STOP Tff7b72= T79c0ff1Tb4b4b4;
Tff7b72return Te6edf3temp Tff7b72* T79c0ff0.25fTb4b4b4; T8b949e// Convert to *C
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::shutdownPeripheralsTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Power off the display if any
Tff7b72#Tff7b72ifdef DISPLAY_CLASS
Tff7b72if Tb4b4b4(Te6edf3displayTb4b4b4.Te6edf3isOnTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3displayTb4b4b4.Te6edf3turnOffTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72#Tff7b72endif
T8b949e// Prep LoRa radio for power down
Tff7b72#Tff7b72ifdef P_LORA_RESET
Te6edf3digitalWriteTb4b4b4(Te6edf3P_LORA_RESETTb4b4b4, Te6edf3HIGHTb4b4b4)Tb4b4b4; T8b949e// preload OUT latch so pinMode can't glitch NRESET low
Te6edf3pinModeTb4b4b4(Te6edf3P_LORA_RESETTb4b4b4, Te6edf3OUTPUTTb4b4b4)Tb4b4b4;
Te6edf3digitalWriteTb4b4b4(Te6edf3P_LORA_RESETTb4b4b4, Te6edf3LOWTb4b4b4)Tb4b4b4; T8b949e// deliberate hardware reset (datasheet: >=100us)
Te6edf3delayMicrosecondsTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4;
Te6edf3digitalWriteTb4b4b4(Te6edf3P_LORA_RESETTb4b4b4, Te6edf3HIGHTb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72if defined(P_LORA_SCLK) && defined(P_LORA_MISO) && defined(P_LORA_MOSI)
Te6edf3SPITb4b4b4.Te6edf3setPinsTb4b4b4(Te6edf3P_LORA_MISOTb4b4b4, Te6edf3P_LORA_SCLKTb4b4b4, Te6edf3P_LORA_MOSITb4b4b4)Tb4b4b4;
Te6edf3SPITb4b4b4.Te6edf3beginTb4b4b4(Tb4b4b4)Tb4b4b4; T8b949e// SPI may not be started on some shutdown paths, need it to shut down radio
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72ifdef P_LORA_BUSY
Te6edf3pinModeTb4b4b4(Te6edf3P_LORA_BUSYTb4b4b4, Te6edf3INPUTTb4b4b4)Tb4b4b4;
Tffa657uint32_t Te6edf3started_at Tff7b72= Te6edf3millisTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72while Tb4b4b4(Te6edf3digitalReadTb4b4b4(Te6edf3P_LORA_BUSYTb4b4b4) Tff7b72&Tff7b72& Te6edf3millisTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3started_at Tff7b72< T79c0ff10Tb4b4b4) Tb4b4b4{Tb4b4b4} T8b949e//wait for radio to be ready
Tff7b72#Tff7b72endif
Tff7b72#Tff7b72ifdef P_LORA_NSS
Te6edf3pinModeTb4b4b4(Te6edf3P_LORA_NSSTb4b4b4, Te6edf3OUTPUTTb4b4b4)Tb4b4b4;
Te6edf3digitalWriteTb4b4b4(Te6edf3P_LORA_NSSTb4b4b4, Te6edf3HIGHTb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
T8b949e// Power off LoRa
Te6edf3radio_driverTb4b4b4.Te6edf3powerOffTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Keep LoRa inactive during deepsleep
Tff7b72#Tff7b72ifdef P_LORA_NSS
Te6edf3digitalWriteTb4b4b4(Te6edf3P_LORA_NSSTb4b4b4, Te6edf3HIGHTb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
T8b949e// Power off GPS if any
Tff7b72ifTb4b4b4(Te6edf3sensorsTb4b4b4.Te6edf3getLocationProviderTb4b4b4(Tb4b4b4) Tff7b72!Tff7b72= Tffa657NULLTb4b4b4) Tb4b4b4{
Te6edf3sensorsTb4b4b4.Te6edf3getLocationProviderTb4b4b4(Tb4b4b4)Tff7b72-Tff7b72>Te6edf3stopTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72#Tff7b72ifdef USE_CC310_HW_CRYPTO
Te6edf3nRFCryptoTb4b4b4.Te6edf3endTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72#Tff7b72endif
T8b949e// Flush serial buffers
Te6edf3SerialTb4b4b4.Te6edf3flushTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3delayTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tffa657void Td2a8ffNRF52Board::powerOffTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3shutdownPeripheralsTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Enter SYSTEMOFF
Tffa657uint8_t Te6edf3sd_enabled Tff7b72= T79c0ff0Tb4b4b4;
Te6edf3sd_softdevice_is_enabledTb4b4b4(Tff7b72&Te6edf3sd_enabledTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3sd_enabledTb4b4b4) Tb4b4b4{ T8b949e// SoftDevice is enabled
Te6edf3sd_power_system_offTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72else Tb4b4b4{ T8b949e// SoftDevice is not enable
Te6edf3NRF_POWERTff7b72-Tff7b72>Te6edf3SYSTEMOFF Tff7b72= Te6edf3POWER_SYSTEMOFF_SYSTEMOFF_EnterTb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tffa657bool Td2a8ffNRF52Board::getBootloaderVersionTb4b4b4(Tffa657charTff7b72* Te6edf3outTb4b4b4, Tffa657size_t Te6edf3max_lenTb4b4b4) Tb4b4b4{
Tff7b72static Tff7b72const Tffa657char Te6edf3BOOTLOADER_MARKERTb4b4b4[Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ffUF2 Bootloader Ta5d6ff"Tb4b4b4;
Tff7b72const Tffa657uint8_tTff7b72* Te6edf3flash Tff7b72= Tb4b4b4(Tff7b72const Tffa657uint8_tTff7b72*Tb4b4b4)T79c0ff0x000FB000Tb4b4b4; T8b949e// earliest known info.txt location is 0xFB90B, latest is 0xFCC4B
Tff7b72for Tb4b4b4(Tffa657uint32_t Te6edf3i Tff7b72= T79c0ff0Tb4b4b4; Te6edf3i Tff7b72< T79c0ff0x3000 Tff7b72- Tb4b4b4(Tff7b72sizeofTb4b4b4(Te6edf3BOOTLOADER_MARKERTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4)Tb4b4b4; Te6edf3iTff7b72+Tff7b72+Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3memcmpTb4b4b4(Tff7b72&Te6edf3flashTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4, Te6edf3BOOTLOADER_MARKERTb4b4b4, Tff7b72sizeofTb4b4b4(Te6edf3BOOTLOADER_MARKERTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4) Tff7b72=Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72const Tffa657charTff7b72* Te6edf3ver Tff7b72= Tb4b4b4(Tff7b72const Tffa657charTff7b72*Tb4b4b4)Tff7b72&Te6edf3flashTb4b4b4[Te6edf3i Tff7b72+ Tff7b72sizeofTb4b4b4(Te6edf3BOOTLOADER_MARKERTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4]Tb4b4b4;
Tffa657size_t Te6edf3len Tff7b72= T79c0ff0Tb4b4b4;
Tff7b72while Tb4b4b4(Te6edf3len Tff7b72< Te6edf3max_len Tff7b72- T79c0ff1 Tff7b72&Tff7b72& Te6edf3verTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72!Tff7b72= Ta5d6ff'Ta5d6ff\0Ta5d6ff' Tff7b72&Tff7b72& Te6edf3verTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72!Tff7b72= Ta5d6ff'Ta5d6ff Ta5d6ff' Tff7b72&Tff7b72& Te6edf3verTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72!Tff7b72= Ta5d6ff'Ta5d6ff\nTa5d6ff' Tff7b72&Tff7b72& Te6edf3verTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72!Tff7b72= Ta5d6ff'Ta5d6ff\rTa5d6ff'Tb4b4b4) Tb4b4b4{
Te6edf3outTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72= Te6edf3verTb4b4b4[Te6edf3lenTb4b4b4]Tb4b4b4;
Te6edf3lenTff7b72+Tff7b72+Tb4b4b4;
Tb4b4b4}
Te6edf3outTb4b4b4[Te6edf3lenTb4b4b4] Tff7b72= Ta5d6ff'Ta5d6ff\0Ta5d6ff'Tb4b4b4;
Tff7b72return Te6edf3len Tff7b72> T79c0ff0Tb4b4b4; T8b949e// bootloader string is non-empty
Tb4b4b4}
Tb4b4b4}
Tff7b72return Tffa657falseTb4b4b4;
Tb4b4b4}
Tffa657bool Td2a8ffNRF52Board::startOTAUpdateTb4b4b4(Tff7b72const Tffa657char Tff7b72*Te6edf3idTb4b4b4, Tffa657char Te6edf3replyTb4b4b4[Tb4b4b4]Tb4b4b4) Tb4b4b4{
T8b949e// Config the peripheral connection with maximum bandwidth
T8b949e// more SRAM required by SoftDevice
T8b949e// Note: All config***() function must be called before begin()
Te6edf3BluefruitTb4b4b4.Te6edf3configPrphBandwidthTb4b4b4(Te6edf3BANDWIDTH_MAXTb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3configPrphConnTb4b4b4(T79c0ff92Tb4b4b4, Te6edf3BLE_GAP_EVENT_LENGTH_MINTb4b4b4, T79c0ff16Tb4b4b4, T79c0ff16Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3BluefruitTb4b4b4.Te6edf3beginTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4) Tff7b72return Tffa657falseTb4b4b4;
T8b949e// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Te6edf3BluefruitTb4b4b4.Te6edf3setTxPowerTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4;
T8b949e// Set the BLE device name
Te6edf3BluefruitTb4b4b4.Te6edf3setNameTb4b4b4(Te6edf3ota_nameTb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3PeriphTb4b4b4.Te6edf3setConnectCallbackTb4b4b4(Te6edf3connect_callbackTb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3PeriphTb4b4b4.Te6edf3setDisconnectCallbackTb4b4b4(Te6edf3disconnect_callbackTb4b4b4)Tb4b4b4;
T8b949e// To be consistent OTA DFU should be added first if it exists
Te6edf3bledfuTb4b4b4.Te6edf3beginTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e// Set up and start advertising
T8b949e// Advertising packet
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3addFlagsTb4b4b4(Te6edf3BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODETb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3addTxPowerTb4b4b4(Tb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3addNameTb4b4b4(Tb4b4b4)Tb4b4b4;
T8b949e/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3restartOnDisconnectTb4b4b4(Tffa657trueTb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3setIntervalTb4b4b4(T79c0ff32Tb4b4b4, T79c0ff244Tb4b4b4)Tb4b4b4; T8b949e// in unit of 0.625 ms
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3setFastTimeoutTb4b4b4(T79c0ff30Tb4b4b4)Tb4b4b4; T8b949e// number of seconds in fast mode
Te6edf3BluefruitTb4b4b4.Te6edf3AdvertisingTb4b4b4.Te6edf3startTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4; T8b949e// 0 = Don't stop advertising after n seconds
Tffa657uint8_t Te6edf3mac_addrTb4b4b4[T79c0ff6Tb4b4b4]Tb4b4b4;
Te6edf3memsetTb4b4b4(Te6edf3mac_addrTb4b4b4, T79c0ff0Tb4b4b4, Tff7b72sizeofTb4b4b4(Te6edf3mac_addrTb4b4b4)Tb4b4b4)Tb4b4b4;
Te6edf3BluefruitTb4b4b4.Te6edf3getAddrTb4b4b4(Te6edf3mac_addrTb4b4b4)Tb4b4b4;
Te6edf3sprintfTb4b4b4(Te6edf3replyTb4b4b4, Ta5d6ff"Ta5d6ffOK - mac: %02X:%02X:%02X:%02X:%02X:%02XTa5d6ff"Tb4b4b4, Te6edf3mac_addrTb4b4b4[T79c0ff5Tb4b4b4]Tb4b4b4, Te6edf3mac_addrTb4b4b4[T79c0ff4Tb4b4b4]Tb4b4b4, Te6edf3mac_addrTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4,
Te6edf3mac_addrTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3mac_addrTb4b4b4[T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3mac_addrTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4)Tb4b4b4;
Tff7b72return Tffa657trueTb4b4b4;
Tb4b4b4}
Tff7b72#Tff7b72endif
Served by rngit 1.5.0 - Generated in 0.13s